#include "Action.h"
#include "MyCommander.h"


namespace EAction
{
    bool IsMoveAction(Type t)
    {
        return _MoveActionsStart < t && t < _MoveActonsEnd;
    }
}


///////////////////////////////////////////////////////////////////////////////////////////////////
CoverPosition::CoverPosition(MyCommander* commander, const string& bot_name, const string& comment, const Vector2&  dir, float time)
: Action(commander, bot_name, comment, EAction::CoverPosition)
{
    m_Time = time;
    m_Direction = dir;
    m_CurrentTime = -1.f;
}

///////////////////////////////////////////////////////////////////////////////////////////////////
void CoverPosition::Update(float dt)
{
    if (m_CurrentTime < 0.f)
    {
        m_CurrentTime = 0.f;
        m_Commander->issue(new DefendCommand(m_BotName, m_Direction, "Cover Position, " + m_Comment));
    }
    else if (m_CurrentTime < m_Time)
        m_CurrentTime += dt;
    else
        m_Result = EResult::Success;
}

///////////////////////////////////////////////////////////////////////////////////////////////////
SimpleMove::SimpleMove(MyCommander* commander, const string& bot_name, const string& comment, const Vector2& dest, bool charge)
: MoveAction(commander, bot_name, comment, EAction::SimpleMove, dest)
, m_OrderIssued(false)
, m_Charge(charge)
{
}

///////////////////////////////////////////////////////////////////////////////////////////////////
void SimpleMove::Update(float /*dt*/)
{
    const BotInfo& bot_info = m_Commander->GetBot(m_BotName);

    if (m_OrderIssued && bot_info.state == BotInfo::STATE_IDLE)
    {
        if (bot_info.position->distance(m_Dest) < 0.5f)
            m_Result = EResult::Success;
        else
            m_Result = EResult::Failure;
    }
    //else if (m_OrderIssued && bot_info.state == BotInfo::STATE_HOLDING)
    //    m_Result = EResult::Failure;
    else if (!m_OrderIssued)
    {
        if (m_Charge)
            m_Commander->issue(new ChargeCommand(m_BotName, m_Dest, "SimpleMove charge, " + m_Comment));
        else
            m_Commander->issue(new AttackCommand(m_BotName, m_Dest, boost::none, "SimpleMove, " + m_Comment));
        m_OrderIssued = true;
    }
}

///////////////////////////////////////////////////////////////////////////////////////////////////
DefensiveMove::DefensiveMove(MyCommander* commander, const string& bot_name, const string& comment, const Vector2& origin)
: Action(commander, bot_name, comment, EAction::DefensiveMove)
, m_Origin(origin)
, m_OrderIssued(false)
{
}

///////////////////////////////////////////////////////////////////////////////////////////////////
void DefensiveMove::Update(float dt)
{
    if (m_Commander->GetGame().team->flag->position.distance(m_Origin) > 0.1f)
    {
        m_Result = EResult::Failure;
        return;
    }

    if (!m_OrderIssued || m_Commander->GetBot(m_BotName).state == BotInfo::STATE_IDLE)
    {
        Path path;

        GeneratePath(path);
        m_Commander->issue(new AttackCommand(m_BotName, path, boost::none, "DefensiveMove, " + m_Comment));
        m_OrderIssued = true;
    }
}

///////////////////////////////////////////////////////////////////////////////////////////////////
void DefensiveMove::GeneratePath(Path& res_path)
{
    float len = 1.5f;
    for (int k = 0; k < 15 + rand() % 10; ++k)
    {
        float random_angle = (float) rand() / RAND_MAX * (PI / 6.f);
        Vector2 base = Utils::Rotate(Vector2(len, 0.f), random_angle);
        int start = rand() % 3;

        for (uint i = 0; i < 4; ++i)
        {
            Vector2 pos = m_Origin + Utils::Rotate(base, PI * 0.5f * (i + start));
            if (m_Commander->GetLevel().blockHeights[(int) pos.x + (int) pos.y * m_Commander->GetLevel().width] > 0.f)
                continue;
            res_path.push_back(pos);
        }
    }
}

///////////////////////////////////////////////////////////////////////////////////////////////////
Move::Move(MyCommander* commander, const string& bot_name, const string& comment, const Vector2& dest, bool charge /*= false*/)
: MoveAction(commander, bot_name, comment, EAction::SimpleMove, dest)
, m_OrderIssued(false)
, m_Charge(charge)
{

}

///////////////////////////////////////////////////////////////////////////////////////////////////
void Move::Update(float dt)
{
    const BotInfo& bot_info = m_Commander->GetBot(m_BotName);

    if (m_OrderIssued)
    {
        if (bot_info.state == BotInfo::STATE_IDLE)
        {
            if (bot_info.position->distance(m_Dest) < 0.5f)
                m_Result = EResult::Success;
            else
                m_Result = EResult::Failure;

            return ;
        }

        //vector<BotInfo*>& enemy_bots = m_Commander->GetGame().enemyTeam->members;
        //for (uint i = 0; i < enemy_bots.size())
        //{
        //    if (enemy_bots[i]->seenlast < 5.f)
        //    {

        //    }
        //}
            
    }
    //else if (m_OrderIssued && bot_info.state == BotInfo::STATE_HOLDING)
    //    m_Result = EResult::Failure;
    else // if (!m_OrderIssued)
    {
        m_Commander->GetPathFinder()->FindPath(*bot_info.position, m_Dest, m_Path, false);
        m_Commander->GetPathFinder()->SmoothPath(m_Path, m_PathSmoothed);

        if (m_Charge)
            m_Commander->issue(new ChargeCommand(m_BotName, m_PathSmoothed, "Move charge, " + m_Comment));
        else
            m_Commander->issue(new AttackCommand(m_BotName, m_PathSmoothed, boost::none, "Move, " + m_Comment));
        m_OrderIssued = true;
    }
}